import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;


public class WhoDecode0001 {

	/** 正在解码的字节 */
	private int reading;
	
	/** 已读取字节数 */
	private int readCount;
	
//	/** 已输出字节数 */
//	private int outCount = 0;

	/** 当前字节已解码/编码位数 */ 
	private int bitCount;

	/** 解码字典,[10H~10FH],256字节 */
	private byte[] decDict = new byte[0x100];

//	/** 压缩数据长度,[110H] */
//	private int binSize;
	
	/** 原文长度,[114H] */
	private int textSize;
	
	/** 压缩数据在文件中的偏移,[118H],值都是0x120 */
	private int pos;
	
	/** 原文 */
	private byte[] text;

	private boolean stopMe;
	
	
	public void decode() {
		stopMe = false;
		File[] files = MainForm.openFiles(".", "bin");
		if (files.length == 0) {
			//System.exit(0);
			MainForm.showMsgBox("not selected");
			return;
		} else {
			File foutdir = new File(files[0].getParent() + "/decoded");
			foutdir.mkdir();
			foutdir = new File(files[0].getParent() + "/GBKtxt");
			foutdir.mkdir();
		}

		String foutName = null;
		FileInputStream fis = null;
		ByteArrayInputStream bais = null;
		DataInputStream dis = null;
		FileOutputStream fos = null;
		
		try {
			for (int file_i=0; file_i<files.length; file_i++) {
				if(stopMe) return;
				MainForm.setProgressBar(files[file_i].getName(), file_i * 3);
				
				byte[] bFile = new byte[(int) files[file_i].length()];
				
				fis = new FileInputStream(files[file_i]);
				fis.read(bFile);
				fis.close();
				bais = new ByteArrayInputStream(bFile);
				dis = new DataInputStream(bais);

				dis.skipBytes(0x10);
				dis.read(decDict);

//				binSize = 
					dis.readInt();
				textSize = dis.readInt();
				pos = dis.readInt();
				
				if (textSize == 0) {
					continue;
				}
				
				dis.reset();
				dis.skipBytes(pos);
				readCount = 0;
				bitCount = 0;
				
				/* decode data array */
				text = new byte[textSize];
				MainForm.setProgressBarValue(file_i *3 +1);
				if (decodeBin2Text(dis, decDict, text) == -1) {
					MainForm.showMsgBox("decode failed");
					return;
				} else {
					MainForm.setProgressBarValue(file_i *3 +2);
					foutName = files[file_i].getParent() + "/decoded/" + files[file_i].getName().substring(0,files[file_i].getName().length()-4) + ".uni";
					File fout = new File(foutName);
					fos = new FileOutputStream(fout);
					fos.write(text);
					fos.close();
					
					foutName = files[file_i].getParent() + "/GBKtxt/" + files[file_i].getName().substring(0,files[file_i].getName().length()-4) + ".txt";
//					System.out.println(foutName);
					saveTxt(text, foutName);
				}
			}
			MainForm.showMsgBox("done");
		} catch (Exception e) {
			MainForm.showMsgBox(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				if (dis != null) {dis.close(); dis = null;}
				if (fis != null) {fis.close(); fis = null;}
				if (fos != null) {fos.close(); fos = null;}
			} catch (IOException e) {
					e.printStackTrace();
			}
		}
	}
	
	private int decodeBin2Text(DataInputStream dis, byte[] decDict, byte[] text) {
		/** 第1个数 */
		int temp;
		/** 超255时读的第2个数 */
		int temp2; 
		/** 原文末端指针 */
		int textCount = 0;
		int textSize = text.length;
		while (textCount < textSize) {
			temp = getCode(dis);
			if (temp >= 0x100) {
				temp -= 0x100;
				if (temp > textCount) {
					return -1;
				}
				temp2 = getCode(dis);
				temp2 += 3;
				for (int i=0; i<temp2; i++) {
					if (textCount >= textSize) {
						return 0;
					}
					text[textCount] = text[textCount - temp];
					textCount++;
				}
			} else {
				text[textCount] = decDict[temp];
				textCount++;
			}
		}
		return 0;
	}
	
	private int getCode(DataInputStream dis) {
		int t1=0, t2, n=0;
		do {
			t2 = getbit(dis, 1);
			t1 = (t1 << 1) + t2;
			n++;
		} while(t2 != 0);
		t2 = getbit(dis, n);
		return t1 + t2;
	}
	
	private int getbit(DataInputStream dis, int n) {
		int t = 0;
		while (n-- != 0) {
			if (bitCount == 0) {
				try {
					reading = dis.readUnsignedByte();
				} catch (EOFException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
				bitCount = 8;
				readCount++;
			}
			bitCount--;
			t = (t << 1) + ((reading & 0x80) >> 7);
			reading <<= 1;
		}
		return t;
	}
	
	private void saveTxt(byte[] b, String txtName) {
		int offset = 2 + 4 * (Util.getUnsignbyte(b[0]) + Util.getUnsignbyte(b[1]) * 0x100);
		try {
			Charset utf16leCharset = Charset.forName("UTF-16LE");
        	Charset gbkCharset = Charset.forName("GBK");
			ByteBuffer inputBuffer = ByteBuffer.wrap(b, offset, b.length - offset);
        	CharBuffer data = utf16leCharset.decode(inputBuffer);
        	ByteBuffer outputBuffer = gbkCharset.encode(data);
        	byte[] bgbk = outputBuffer.array();
        	
        	/** bgbk.length = data.length * 2, ByteBuffer尾部会剩下很多空字节，不知如何处理 */
        	int validLen = bgbk.length;
        	for (int i = validLen-1; i >= 0; i--) {
				if(bgbk[i] != 0){
					validLen = i+1;
					break;
				}
			}
        	
        	String head = "\r\n\r\n\r\n===="+txtName.substring(txtName.length()-12, txtName.length()-4)+".txt====\r\n\r\n\r\n";
        	byte[] bhead = head.getBytes();

        	FileOutputStream fos = new FileOutputStream(new File(txtName));
        	fos.write(bhead);
			fos.write(bgbk,0,validLen);
			fos.flush();
			fos.close();
			fos = null;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
//	private void saveTxt1(byte[] b, String txtName) {
//		PrintStream p = null;
//		try {
//			p = new PrintStream(new BufferedOutputStream(new FileOutputStream(txtName)));
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		}
//		System.setOut(p);
//		System.out.println("===="+txtName.substring(txtName.length()-12, txtName.length()-4)+".txt====");
//		System.out.println();
//		System.out.println();
//		showTxt(b);
//		System.out.println();
//		System.out.println();
//		System.out.println();
//		System.out.flush();
//		p.close();
//		System.setOut(System.out);
//	}
//	private void showTxt(byte[] b) {
//        try {
//    		System.out.print(new String(b,"UTF-16LE").trim());
//		} catch (UnsupportedEncodingException e) {
//			e.printStackTrace();
//		}
//	}
	public void stopMe(){
		stopMe  = true;
	}
	
}
